#pragma once

#include "base.h"
#include "../impl/ohlc.h"

namespace mdtx::online::updater
{
    template <typename T>
    class ohlc_tumbling : public updater_base<T, T, 1, 4>,
                          public impl::ohlc<T, false>
    {
        using base = updater_base<T, T, 1, 4>;
        using ibase = impl::ohlc<T, false>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->o, this->h, this->l, this->c);
        }
    };

    template <typename T>
    class ohlc_sliding : public updater_base<T, T, 1, 4>,
                         public impl::ohlc<T, true>
    {
        using base = updater_base<T, T, 1, 4>;
        using ibase = impl::ohlc<T, true>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::ibase;
        using ibase::insert_impl;
        using ibase::remove_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in));
        }

        void remove(tuple_in const &in) override
        {
            remove_impl(std::get<0>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->buf.front(), this->max.front(), this->min.front(), this->buf.back());
        }
    };

    template <typename T>
    class ohlc4_tumbling : public updater_base<T, T, 4, 4>,
                           public impl::ohlc4<T>
    {
        using base = updater_base<T, T, 4, 4>;
        using ibase = impl::ohlc4<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in), std::get<1>(in), std::get<2>(in), std::get<3>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            return tuple_out(this->o, this->h, this->l, this->c);
        }
    };

    template <typename T>
    class vwap : public updater_base<T, T, 2, 3>,
                 public impl::vwap<T>
    {
        using base = updater_base<T, T, 2, 3>;
        using ibase = impl::vwap<T>;

    public:
        using typename base::tuple_in;
        using typename base::tuple_out;
        using base::insert;
        using base::remove;

        using ibase::insert_impl;
        using ibase::remove_impl;
        using ibase::reset_impl;

        void insert(tuple_in const &in) override
        {
            insert_impl(std::get<0>(in), std::get<1>(in));
        }

        void remove(tuple_in const &in) override
        {
            remove_impl(std::get<0>(in), std::get<1>(in));
        }

        void reset() override
        {
            reset_impl();
        }

        tuple_out get() override
        {
            T vo = this->vol;
            T tn = this->tnvr;
            T ap{};
            if (vo > 0)
            {
                ap = tn / vo;
            }
            return tuple_out(vo, tn, ap);
        }
    };
}
